<!doctype html>
<html lang="zh-Hans" dir="ltr" class="docs-wrapper docs-doc-page docs-version-current plugin-docs plugin-id-default docs-doc-id-action/springfox/springfox10">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="generator" content="Docusaurus v2.0.1">
<link rel="search" type="application/opensearchdescription+xml" title="Knife4j" href="/opensearch.xml">

<!-- Google Tag Manager -->
    <script>!function(e,t,a,n,g){e[n]=e[n]||[],e[n].push({"gtm.start":(new Date).getTime(),event:"gtm.js"});var m=t.getElementsByTagName(a)[0],r=t.createElement(a);r.async=!0,r.src="https://www.googletagmanager.com/gtm.js?id=GTM-TKBX678",m.parentNode.insertBefore(r,m)}(window,document,"script","dataLayer")</script>
    <!-- End Google Tag Manager -->
<script src="/js/custom.js"></script>
<script src="/js/baidu.js"></script>
<script src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-1589206801610969" async crossorigin="anonymous"></script><title data-rh="true">springfox 源码分析(十) 遍历接口获取Model对象 | Knife4j</title><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:url" content="https://doc.xiaominfo.com/docs/action/springfox/springfox10"><meta data-rh="true" name="docusaurus_locale" content="zh-Hans"><meta data-rh="true" name="docsearch:language" content="zh-Hans"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-default-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-default-current"><meta data-rh="true" property="og:title" content="springfox 源码分析(十) 遍历接口获取Model对象 | Knife4j"><meta data-rh="true" name="description" content="在上一篇中,我们了解到了springfox通过groupName的过滤,拿到了所有的接口,并且通过guava库的ArrayListMultimap对接口的Controller进一步进行了分组,接下来就是解析每个接口的操作了"><meta data-rh="true" property="og:description" content="在上一篇中,我们了解到了springfox通过groupName的过滤,拿到了所有的接口,并且通过guava库的ArrayListMultimap对接口的Controller进一步进行了分组,接下来就是解析每个接口的操作了"><link data-rh="true" rel="icon" href="/img/favicon.ico"><link data-rh="true" rel="canonical" href="https://doc.xiaominfo.com/docs/action/springfox/springfox10"><link data-rh="true" rel="alternate" href="https://doc.xiaominfo.com/docs/action/springfox/springfox10" hreflang="zh-Hans"><link data-rh="true" rel="alternate" href="https://doc.xiaominfo.com/docs/action/springfox/springfox10" hreflang="x-default"><link data-rh="true" rel="preconnect" href="https://3CRIMRK623-dsn.algolia.net" crossorigin="anonymous"><link rel="stylesheet" href="/assets/css/styles.66359a73.css">
<link rel="preload" href="/assets/js/runtime~main.e0db172c.js" as="script">
<link rel="preload" href="/assets/js/main.c059fb6e.js" as="script">
</head>
<body class="navigation-with-keyboard">
<script>!function(){function e(e){document.documentElement.setAttribute("data-theme",e)}var t=function(){var e=null;try{e=localStorage.getItem("theme")}catch(e){}return e}();null!==t?e(t):window.matchMedia("(prefers-color-scheme: dark)").matches?e("dark"):window.matchMedia("(prefers-color-scheme: light)").matches?e("light"):e("dark")}()</script><div id="__docusaurus">
<div role="region"><a href="#" class="skipToContent_fXgn">跳到主要内容</a></div><nav class="navbar navbar--fixed-top navbarHideable_m1mJ"><div class="navbar__inner"><div class="navbar__items"><button aria-label="Navigation bar toggle" class="navbar__toggle clean-btn" type="button" tabindex="0"><svg width="30" height="30" viewBox="0 0 30 30" aria-hidden="true"><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg></button><a class="navbar__brand" href="/"><div class="navbar__logo"><img src="/img/knife4j-light.svg" alt="" class="themedImage_ToTc themedImage--light_HNdA"><img src="/img/knife4j-dark.svg" alt="" class="themedImage_ToTc themedImage--dark_i4oU"></div><b class="navbar__title text--truncate">Knife4j</b></a><a class="navbar__item navbar__link" href="/docs/quick-start">文档</a><a class="navbar__item navbar__link changelog" href="/docs/middleware-sources">中间件</a><a class="navbar__item navbar__link changelog" href="/docs/oas">OAS规范</a><a aria-current="page" class="navbar__item navbar__link changelog navbar__link--active" href="/docs/action">实战指南</a><a class="navbar__item navbar__link changelog" href="/docs/changelog">更新日志</a><a class="navbar__item navbar__link changelog" href="/docs/faq">FAQ</a><div class="navbar__item dropdown dropdown--hoverable"><a href="#" aria-haspopup="true" aria-expanded="false" role="button" class="navbar__link">旧版本</a><ul class="dropdown__menu"><li><a class="dropdown__link" target="_blank" href="/v2/index.html">2.0.9</a></li></ul></div></div><div class="navbar__items navbar__items--right"><div class="toggle_MW0i colorModeToggle_x44X"><button class="clean-btn toggleButton_yw5v toggleButtonDisabled_BJd7" type="button" disabled="" title="切换浅色/暗黑模式（当前为暗黑模式）" aria-label="切换浅色/暗黑模式（当前为暗黑模式）"><span><svg viewBox="0 0 13 12" fill="none" xmlns="http://www.w3.org/2000/svg" width="14" height="14" class="lightToggleIcon_SFTY"><g clip-path="url(#clip0_833_8168)"><path d="M6.59998 8.49999C7.98069 8.49999 9.09998 7.3807 9.09998 5.99999C9.09998 4.61928 7.98069 3.49999 6.59998 3.49999C5.21926 3.49999 4.09998 4.61928 4.09998 5.99999C4.09998 7.3807 5.21926 8.49999 6.59998 8.49999Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></path><path d="M6.59985 0.5V1.5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></path><path d="M6.59985 10.5V11.5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></path><path d="M2.7099 2.11L3.4199 2.82" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></path><path d="M9.77991 9.17999L10.4899 9.88999" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></path><path d="M1.09998 6H2.09998" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></path><path d="M11.0999 6H12.0999" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></path><path d="M2.7099 9.88999L3.4199 9.17999" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></path><path d="M9.77991 2.82L10.4899 2.11" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></path></g><defs><clipPath id="clip0_833_8168"><rect width="12" height="12" fill="white" transform="translate(0.599976)"></rect></clipPath></defs></svg><svg viewBox="0 0 13 12" width="14" height="14" class="darkToggleIcon_ekgs"><path d="M10.7001 6.39501C10.6215 7.24611 10.3021 8.05721 9.77927 8.7334C9.25646 9.40959 8.55189 9.92291 7.748 10.2133C6.9441 10.5036 6.07414 10.5591 5.2399 10.3731C4.40565 10.187 3.64164 9.76728 3.03726 9.1629C2.43287 8.55851 2.01312 7.7945 1.8271 6.96026C1.64108 6.12602 1.6965 5.25605 1.98688 4.45216C2.27725 3.64826 2.79056 2.94369 3.46675 2.42088C4.14294 1.89808 4.95404 1.57866 5.80515 1.50001C5.30685 2.17414 5.06707 3.00473 5.12941 3.84071C5.19175 4.6767 5.55208 5.46254 6.14485 6.05531C6.73762 6.64808 7.52346 7.0084 8.35944 7.07074C9.19542 7.13308 10.026 6.8933 10.7001 6.39501Z" stroke="currentColor" fill="transparent" stroke-linecap="round" stroke-linejoin="round"></path></svg></span></button></div><a href="https://github.com/xiaoymin/swagger-bootstrap-ui" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link icon" title="View on GitHub">GitHub<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a><div class="searchBox_ZlJk"><button type="button" class="DocSearch DocSearch-Button" aria-label="搜索"><span class="DocSearch-Button-Container"><svg width="20" height="20" class="DocSearch-Search-Icon" viewBox="0 0 20 20"><path d="M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z" stroke="currentColor" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"></path></svg><span class="DocSearch-Button-Placeholder">搜索</span></span><span class="DocSearch-Button-Keys"></span></button></div></div></div><div role="presentation" class="navbar-sidebar__backdrop"></div></nav><div class="main-wrapper mainWrapper_z2l0 docsWrapper_BCFX"><button aria-label="回到顶部" class="clean-btn theme-back-to-top-button backToTopButton_sjWU" type="button"></button><div class="docPage__5DB"><aside class="theme-doc-sidebar-container docSidebarContainer_b6E3"><div class="sidebar_njMd sidebarWithHideableNavbar_wUlq"><a tabindex="-1" class="sidebarLogo_isFc" href="/"><img src="/img/knife4j-light.svg" alt="" class="themedImage_ToTc themedImage--light_HNdA"><img src="/img/knife4j-dark.svg" alt="" class="themedImage_ToTc themedImage--dark_i4oU"><b>Knife4j</b></a><nav class="menu thin-scrollbar menu_SIkG"><ul class="theme-doc-sidebar-menu menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menuHtmlItem_M9Kj menu__list-item">
<div class="sidebar_donate">
    <div class="sidebar_sponsor">
        <a target="_blank" href="https://www.apifox.com/apiskills/apifox-auto-generates-api-docs/?utm_source=pay&utm_medium=knife4jg"><img src="/images/sponsor/apifox/Apifox IDEA@3x.png">
        </a>
    </div>
    <div class="sidebar_sponsor_submit">
        <a href="/docs/community/donate">成为赞助商</a>
    </div>
<div>
</div></div></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/docs/action">实战指南</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/docs/action/action-simple">示例代码</a></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist menu__link--sublist-caret" aria-expanded="false" href="/docs/action/mavenbom">Spring 单体架构</a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist menu__link--sublist-caret" aria-expanded="false" href="/docs/action/springcloud-gateway">Spring微服务架构</a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist menu__link--sublist-caret" aria-expanded="false" href="/docs/action/oauth2-implicit">OAuth2.0</a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist menu__link--sublist-caret" aria-expanded="false" href="/docs/action/aggregation-disk">微服务聚合实战</a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist menu__link--sublist-caret" aria-expanded="false" href="/docs/action/dotnetcore-knife4j-how">ASP.NET Core</a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist menu__link--active" aria-expanded="true" href="/docs/action/springfox">Springfox 源码系列</a><button aria-label="打开/收起侧边栏菜单「Springfox 源码系列」" type="button" class="clean-btn menu__caret"></button></div><ul style="display:block;overflow:visible;height:auto" class="menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/action/springfox/springfox1">springfox 源码分析(一) 程序入口</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/action/springfox/springfox2">springfox 源码分析(二) 初探mapstruct</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/action/springfox/springfox3">springfox 源码分析(三) 初探Spring Plugin插件系统</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/action/springfox/springfox4">springfox 源码分析(四) 配置类初始化</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/action/springfox/springfox5">springfox 源码分析(五) web配置类Plugin插件的使用</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/action/springfox/springfox6">springfox 源码分析(六) web配置类扫描包作用探索</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/action/springfox/springfox7">springfox 源码分析(七) 文档初始化</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/action/springfox/springfox8">springfox 源码分析(八) 遍历接口获取Model对象</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/action/springfox/springfox9">springfox 源码分析(九) 文档初始化-分组</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link menu__link--active" aria-current="page" tabindex="0" href="/docs/action/springfox/springfox10">springfox 源码分析(十) 遍历接口获取Model对象</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/action/springfox/springfox11">springfox 源码分析(十一) 自定义添加Swagger Models功能实现</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/action/springfox/springfox12">springfox 源码分析(十二) 遍历接口获取ApiDescription集合</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/action/springfox/springfox13">springfox 源码分析(十三) 自定义扩展实现接口的排序</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/action/springfox/springfox14">springfox 源码分析(十四) 归档得到ApiListing接口集合</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/action/springfox/springfox15">springfox 源码分析(十五) 归档得到Documentation文档对象</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/action/springfox/springfox16">springfox 源码分析(十六) 分组接口swagger-resouces</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/action/springfox/springfox17">springfox 源码分析(十七) Swagger2接口文档示例接口api-docs</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/action/springfox/springfox18">springfox 源码分析(十八) 自定义扩展实现分组的排序</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/action/springfox/springfox19">springfox 源码分析(十九) guava库学习</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/action/springfox/springfox20">springfox 源码分析(二十) 自定义扩展实现Map、JSONObject等动态字段显示</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/action/springfox/springfox21">springfox 源码分析(二十一) 忽略参数Class类型</a></li></ul></li></ul></nav><button type="button" title="收起侧边栏" aria-label="收起侧边栏" class="button button--secondary button--outline collapseSidebarButton_PEFL"><svg width="20" height="20" aria-hidden="true" class="collapseSidebarButtonIcon_kv0_"><g fill="#7a7a7a"><path d="M9.992 10.023c0 .2-.062.399-.172.547l-4.996 7.492a.982.982 0 01-.828.454H1c-.55 0-1-.453-1-1 0-.2.059-.403.168-.551l4.629-6.942L.168 3.078A.939.939 0 010 2.528c0-.548.45-.997 1-.997h2.996c.352 0 .649.18.828.45L9.82 9.472c.11.148.172.347.172.55zm0 0"></path><path d="M19.98 10.023c0 .2-.058.399-.168.547l-4.996 7.492a.987.987 0 01-.828.454h-3c-.547 0-.996-.453-.996-1 0-.2.059-.403.168-.551l4.625-6.942-4.625-6.945a.939.939 0 01-.168-.55 1 1 0 01.996-.997h3c.348 0 .649.18.828.45l4.996 7.492c.11.148.168.347.168.55zm0 0"></path></g></svg></button></div></aside><main class="docMainContainer_gTbr"><div class="container padding-top--md padding-bottom--lg"><div class="row"><div class="col docItemCol_z5aJ"><div class="docItemContainer_c0TR"><article><nav class="theme-doc-breadcrumbs breadcrumbsContainer_Z_bl" aria-label="页面路径"><ul class="breadcrumbs" itemscope="" itemtype="https://schema.org/BreadcrumbList"><li class="breadcrumbs__item"><a aria-label="主页面" class="breadcrumbs__link" href="/"><svg viewBox="0 0 24 24" class="breadcrumbHomeIcon_OVgt"><path d="M10 19v-5h4v5c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-7h1.7c.46 0 .68-.57.33-.87L12.67 3.6c-.38-.34-.96-.34-1.34 0l-8.36 7.53c-.34.3-.13.87.33.87H5v7c0 .55.45 1 1 1h3c.55 0 1-.45 1-1z" fill="currentColor"></path></svg></a></li><li itemscope="" itemprop="itemListElement" itemtype="https://schema.org/ListItem" class="breadcrumbs__item"><a class="breadcrumbs__link" itemprop="item" href="/docs/action/springfox"><span itemprop="name">Springfox 源码系列</span></a><meta itemprop="position" content="1"></li><li itemscope="" itemprop="itemListElement" itemtype="https://schema.org/ListItem" class="breadcrumbs__item breadcrumbs__item--active"><span class="breadcrumbs__link" itemprop="name">springfox 源码分析(十) 遍历接口获取Model对象</span><meta itemprop="position" content="2"></li></ul></nav><div class="tocCollapsible_ETCw theme-doc-toc-mobile tocMobile_ITEo"><button type="button" class="clean-btn tocCollapsibleButton_TO0P">本页总览</button></div><div class="theme-doc-markdown markdown"><h1>springfox 源码分析(十) 遍历接口获取Model对象</h1><p>在上一篇中,我们了解到了springfox通过groupName的过滤,拿到了所有的接口,并且通过guava库的<code>ArrayListMultimap</code>对接口的Controller进一步进行了分组,接下来就是解析每个接口的操作了</p><p>这篇主要介绍springfox解析每个接口中涉及的Model类操作,这其中包含：</p><ul><li>参数中是Java Bean的参数类型</li><li>接口返回非void、基础类型的类型</li><li>在<code>@ApiResponse</code>注解中标注返回的class类型</li></ul><p>目前主要有以上这三种类型,通过解析拿到接口涉及的Model类型,然后添加到一个Set集合中,该Set集合就对应了Swagger标准属性的definitions属性</p><p>先来看遍历接口的代码：</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">for (final ResourceGroup resourceGroup : sortedByName(allResourceGroups)) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  DocumentationContext documentationContext = context.getDocumentationContext();</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Set&lt;String&gt; produces = new LinkedHashSet&lt;String&gt;(documentationContext.getProduces());</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Set&lt;String&gt; consumes = new LinkedHashSet&lt;String&gt;(documentationContext.getConsumes());</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  String host = documentationContext.getHost();</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Set&lt;String&gt; protocols = new LinkedHashSet&lt;String&gt;(documentationContext.getProtocols());</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Set&lt;ApiDescription&gt; apiDescriptions = newHashSet();</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Map&lt;String, Model&gt; models = new LinkedHashMap&lt;String, Model&gt;();</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  //得到该Controller下的所有接口</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  List&lt;RequestMappingContext&gt; requestMappings = nullToEmptyList(requestMappingsByResourceGroup.get(resourceGroup));</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  for (RequestMappingContext each : sortedByMethods(requestMappings)) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    //拿到该接口的所有Model</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    models.putAll(apiModelReader.read(each.withKnownModels(models)));</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    apiDescriptions.addAll(apiDescriptionReader.read(each));</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  }</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>遍历<code>RequestMappingContext</code>对象,在前面我也已经介绍过,该对象其实就是每个接口实例对象</p><p>最主要的是来看<code>apiModelReader.read</code>方法</p><p><code>each.withKnownModels</code>方法是通过new关键字复制了一个新的<code>RequestMappingContext</code></p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">public RequestMappingContext withKnownModels(Map&lt;String, Model&gt; knownModels) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    return new RequestMappingContext(documentationContext, handler,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                                     operationModelContextsBuilder, requestMappingPattern, knownModels);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>来看读取接口Models的源码：</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">/***</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   * 读取该接口Model信息</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   * @param context</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   * @return</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   */</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">public Map&lt;String, Model&gt; read(RequestMappingContext context) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    //忽略的class集合，如果没有额外设置,则得到的是Defaults类中的默认忽略类Class集合</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    Set&lt;Class&gt; ignorableTypes = newHashSet(context.getIgnorableParameterTypes());</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    Set&lt;ModelContext&gt; modelContexts = pluginsManager.modelContexts(context);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    Map&lt;String, Model&gt; modelMap = newHashMap(context.getModelMap());</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    for (ModelContext each : modelContexts) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        markIgnorablesAsHasSeen(typeResolver, ignorableTypes, each);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        Optional&lt;Model&gt; pModel = modelProvider.modelFor(each);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        if (pModel.isPresent()) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            LOG.debug(&quot;Generated parameter model id: {}, name: {}, schema: {} models&quot;,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                      pModel.get().getId(),</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                      pModel.get().getName());</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            mergeModelMap(modelMap, pModel.get());</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        } else {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            LOG.debug(&quot;Did not find any parameter models for {}&quot;, each.getType());</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        populateDependencies(each, modelMap);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    return modelMap;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>初步通过源码得知,要想先得到Model,则需要先构造得到ModelContext</p><ul><li>初始化外部涉及到的忽略类型Set集合</li><li>读取RequestMappingContext，拿到ModelContext的Set集合</li><li>context中的ModelMap在此处其实是空对象，对应的modelMap也是空对象,这个在上面的<code>withKnownModels</code>方法中我们可以观察到</li><li>遍历ModelContext的Set集合,通过modelProvider.modelFor的方法由ModelContext转换构造成目标Model对象</li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="modelcontext">ModelContext<a class="hash-link" href="#modelcontext" title="标题的直接链接">​</a></h2><p>在初始化ModelContext集合之前,我们先来看看ModelContext的属性</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">public class ModelContext {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    //类型</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  private final Type type;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    //是否返回类型</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  private final boolean returnType;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    //分组名称</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  private final String groupName;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    //文档类型</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  private final DocumentationType documentationType;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  //父级</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  private final ModelContext parentContext;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    //ResolvedType</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  private final Set&lt;ResolvedType&gt; seenTypes = newHashSet();</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    //model构造器</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  private final ModelBuilder modelBuilder;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  private final AlternateTypeProvider alternateTypeProvider;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    //名称策略</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  private final GenericTypeNamingStrategy genericNamingStrategy;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    //忽略类型</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  private final ImmutableSet&lt;Class&gt; ignorableTypes;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  private ModelContext(</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      String groupName,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      Type type,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      boolean returnType,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      DocumentationType documentationType,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      AlternateTypeProvider alternateTypeProvider,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      GenericTypeNamingStrategy genericNamingStrategy,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      ImmutableSet&lt;Class&gt; ignorableTypes) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    this.groupName = groupName;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    this.documentationType = documentationType;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    this.alternateTypeProvider = alternateTypeProvider;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    this.genericNamingStrategy = genericNamingStrategy;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    this.ignorableTypes = ignorableTypes;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    this.parentContext = null;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    this.type = type;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    this.returnType = returnType;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    this.modelBuilder = new ModelBuilder();</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> //...   </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>参数对象全部是final关键字修饰</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="初始化modelcontext-set集合">初始化ModelContext Set集合<a class="hash-link" href="#初始化modelcontext-set集合" title="标题的直接链接">​</a></h2><p>先来看<code>pluginsManager.modelContexts</code>方法中的初始化操作</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">public Set&lt;ModelContext&gt; modelContexts(RequestMappingContext context) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    DocumentationType documentationType = context.getDocumentationContext().getDocumentationType();</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    //构建该接口的ModelContext集合</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    for (OperationModelsProviderPlugin each : operationModelsProviders.getPluginsFor(documentationType)) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      each.apply(context);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    return context.operationModelsBuilder().build();</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  }</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>通过文档类型,获取Model的<code>OperationModelsProviderPlugin</code>插件实现类，然后调用apply方法初始化</p><p><code>OperationModelsProviderPlugin</code>主要有两个实现类，分别是：</p><ul><li><strong>OperationModelsProviderPlugin</strong>：处理返回类型、参数类型等</li><li><strong>SwaggerOperationModelsProvider</strong>：处理swagger注解提供的值类型,主要包括<code>@ApiResponse</code>、<code>@ApiOperation</code></li></ul><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="operationmodelsproviderplugin">OperationModelsProviderPlugin<a class="hash-link" href="#operationmodelsproviderplugin" title="标题的直接链接">​</a></h3><p>先来看常规类型</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">@Component</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">@Order(Ordered.HIGHEST_PRECEDENCE)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">public class OperationModelsProvider implements OperationModelsProviderPlugin {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  private static final Logger LOG = LoggerFactory.getLogger(OperationModelsProvider.class);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  private final TypeResolver typeResolver;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  @Autowired</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  public OperationModelsProvider(TypeResolver typeResolver) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    this.typeResolver = typeResolver;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  @Override</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  public void apply(RequestMappingContext context) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    collectFromReturnType(context);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    collectParameters(context);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    collectGlobalModels(context);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>常规Model插件的apply方法主要有三个方法</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="collectfromreturntype">collectFromReturnType<a class="hash-link" href="#collectfromreturntype" title="标题的直接链接">​</a></h4><p>收集接口返回类型,跟踪源码;</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">private void collectFromReturnType(RequestMappingContext context) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    ResolvedType modelType = context.getReturnType();</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    modelType = context.alternateFor(modelType);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    LOG.debug(&quot;Adding return parameter of type {}&quot;, resolvedTypeSignature(modelType).or(&quot;&lt;null&gt;&quot;));</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    context.operationModelsBuilder().addReturn(modelType);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  }</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>直接拿到接口的返回类型,这个返回类型在前面接口初始化时,已经初始化，getReturnType方法实际调用的是RequestHandler的方法</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">public ResolvedType getReturnType() {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    return handler.getReturnType();</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>我们在前面也介绍过，RequestHander因为是接口，在springfox中的实现类是<code>WebMvcRequestHandler</code></p><p>拿到返回类型,最终用addReturn方法添加到context对象中的全局<code>Set&lt;ModelContext&gt;</code>对象中</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="collectparameters">collectParameters<a class="hash-link" href="#collectparameters" title="标题的直接链接">​</a></h4><p>收集接口中的参数类型.</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">private void collectParameters(RequestMappingContext context) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    LOG.debug(&quot;Reading parameters models for handlerMethod |{}|&quot;, context.getName());</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    List&lt;ResolvedMethodParameter&gt; parameterTypes = context.getParameters();</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    for (ResolvedMethodParameter parameterType : parameterTypes) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        if (parameterType.hasParameterAnnotation(RequestBody.class)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            || parameterType.hasParameterAnnotation(RequestPart.class)) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          ResolvedType modelType = context.alternateFor(parameterType.getParameterType());</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          LOG.debug(&quot;Adding input parameter of type {}&quot;, resolvedTypeSignature(modelType).or(&quot;&lt;null&gt;&quot;));</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          context.operationModelsBuilder().addInputParam(modelType);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    LOG.debug(&quot;Finished reading parameters models for handlerMethod |{}|&quot;, context.getName());</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  }</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>接口参数类型中,springfox目前只解析两种</p><ul><li>一种是实体类通过Spring的<code>@RequestBody</code>注解标注的,我们在使用Spring开发的时候如果使用该注解通常是使用的JSON作为接口的交互格式</li><li>通过Spring的<code>@ReuqestPart</code>注解标注的参数类型，<code>@RequestPart</code>注解是配合文件上传时附属参数类型使用的注解</li></ul><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="collectglobalmodels">collectGlobalModels<a class="hash-link" href="#collectglobalmodels" title="标题的直接链接">​</a></h4><p>收集接口的全局Model</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">private void collectGlobalModels(RequestMappingContext context) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    for (ResolvedType each : context.getAdditionalModels()) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        context.operationModelsBuilder().addInputParam(each);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        context.operationModelsBuilder().addReturn(each);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>收集外部全局添加的Model,添加进入集合中</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="swaggeroperationmodelsprovider">SwaggerOperationModelsProvider<a class="hash-link" href="#swaggeroperationmodelsprovider" title="标题的直接链接">​</a></h3><p>基于Swagger相关注解赋值的类型Class解析</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">@Component</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">@Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">public class SwaggerOperationModelsProvider implements OperationModelsProviderPlugin {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  private static final Logger LOG = LoggerFactory.getLogger(SwaggerOperationModelsProvider.class);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  private final TypeResolver typeResolver;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  @Autowired</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  public SwaggerOperationModelsProvider(TypeResolver typeResolver) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    this.typeResolver = typeResolver;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  @Override</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  public void apply(RequestMappingContext context) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    collectFromApiOperation(context);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    collectApiResponses(context);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>主要有两种类型：</p><p>收集使用<code>@ApiOperation</code>注解时,使用主句的属性值</p><p>收集<code>@ApiResponse</code>响应状态码涉及到的Model</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="collectfromapioperation">collectFromApiOperation<a class="hash-link" href="#collectfromapioperation" title="标题的直接链接">​</a></h4><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">private void collectFromApiOperation(RequestMappingContext context) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    ResolvedType returnType = context.getReturnType();</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    returnType = context.alternateFor(returnType);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    Optional&lt;ResolvedType&gt; returnParameter = context.findAnnotation(ApiOperation.class)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        .transform(resolvedTypeFromOperation(typeResolver, returnType));</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    if (returnParameter.isPresent() &amp;&amp; returnParameter.get() != returnType) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      LOG.debug(&quot;Adding return parameter of type {}&quot;, resolvedTypeSignature(returnParameter.get()).or(&quot;&lt;null&gt;&quot;));</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      context.operationModelsBuilder().addReturn(returnParameter.get());</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  }</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>查找注解,获取ResolvedType的值</p><p>核心是拿到ApiOeration注解的response-class属性值</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">@VisibleForTesting</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">static ResolvedType getResolvedType(</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    ApiOperation annotation,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    TypeResolver resolver,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    ResolvedType defaultType) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    if (null != annotation) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        Class&lt;?&gt; response = annotation.response();</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        String responseContainer = annotation.responseContainer();</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        if (resolvedType(resolver, response, responseContainer).isPresent()) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            return resolvedType(resolver, response, responseContainer).get();</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    return defaultType;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="collectapiresponses">collectApiResponses<a class="hash-link" href="#collectapiresponses" title="标题的直接链接">​</a></h4><p>收集在接口上标注状态码涉及的Class类，ApiResponses是集合，最终遍历得到ApiResponse</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">private void collectApiResponses(RequestMappingContext context) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  List&lt;ApiResponses&gt; allApiResponses = context.findAnnotations(ApiResponses.class);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  LOG.debug(&quot;Reading parameters models for handlerMethod |{}|&quot;, context.getName());</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Set&lt;ResolvedType&gt; seenTypes = newHashSet();</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  for (ApiResponses apiResponses : allApiResponses) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    List&lt;ResolvedType&gt; modelTypes = toResolvedTypes(context).apply(apiResponses);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    for (ResolvedType modelType : modelTypes) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      if (!seenTypes.contains(modelType)) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        seenTypes.add(modelType);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        context.operationModelsBuilder().addReturn(modelType);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="modelcontext初始化">ModelContext初始化<a class="hash-link" href="#modelcontext初始化" title="标题的直接链接">​</a></h2><p>我们通过TypeResolved方法将基础的Class转换为ResolvedType</p><p>此时ModelContext提供了几个方法将ResolvedType转换为ModelContext类型</p><ul><li>returnValue:提供返回的class</li><li>inputParam:参数类的方法</li></ul><p>通过<code>OperationModelContextsBuilder</code>提供的默认参数,构造函数默认构造出ModelContext对象</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">/**</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   * Convenience method to provide an new context for an input parameter</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   *</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   * @param group                 - group name of the docket</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   * @param type                  - type</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   * @param documentationType     - for documentation type</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   * @param alternateTypeProvider - alternate type provider</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   * @param genericNamingStrategy - how generic types should be named</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   * @param ignorableTypes        - types that can be ignored</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   * @return new context</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   */</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">public static ModelContext inputParam(</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    String group,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    Type type,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    DocumentationType documentationType,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    AlternateTypeProvider alternateTypeProvider,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    GenericTypeNamingStrategy genericNamingStrategy,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    ImmutableSet&lt;Class&gt; ignorableTypes) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    return new ModelContext(</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        group,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        type,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        false,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        documentationType,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        alternateTypeProvider,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        genericNamingStrategy,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        ignorableTypes);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="modelcontext转化为model">ModelContext转化为Model<a class="hash-link" href="#modelcontext转化为model" title="标题的直接链接">​</a></h2><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">Set&lt;ModelContext&gt; modelContexts = pluginsManager.modelContexts(context);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Map&lt;String, Model&gt; modelMap = newHashMap(context.getModelMap());</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">for (ModelContext each : modelContexts) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    //添加基础忽略类型的ResolvedType类型</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    markIgnorablesAsHasSeen(typeResolver, ignorableTypes, each);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    //通过modelProvider获取到Model类型,modelProvider是接口,有两个实现类</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    //DefaultModelProvider:默认装换</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    //CachingModelProvider:缓存</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    Optional&lt;Model&gt; pModel = modelProvider.modelFor(each);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    if (pModel.isPresent()) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        LOG.debug(&quot;Generated parameter model id: {}, name: {}, schema: {} models&quot;,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                  pModel.get().getId(),</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                  pModel.get().getName());</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        mergeModelMap(modelMap, pModel.get());</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    } else {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        LOG.debug(&quot;Did not find any parameter models for {}&quot;, each.getType());</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    populateDependencies(each, modelMap);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>通过modelProvider将ModelContext转换为Model类型</p><p>modelProvider是接口,有两个实现类：</p><ul><li>DefaultModelProvider:默认装换,每次都会将modelContext转换为model</li><li>CachingModelProvider:声明了一个guava的缓存池,先从缓存池获取,如果没有，则调用默认的处理器,转换为model，然后放入缓存池中</li></ul><p>此处modelProvider使用的是caching缓存配置</p><p>初次通过modelFor获取是为空的,所以接下来看<code>populateDependencies</code>方法</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">private void populateDependencies(ModelContext modelContext, Map&lt;String, Model&gt; modelMap) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    Map&lt;String, Model&gt; dependencies = modelProvider.dependencies(modelContext);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    for (Model each : dependencies.values()) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        mergeModelMap(modelMap, each);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>caching默认是依赖default的，此处dependencies实际是调用的default的</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">@Override</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">public Map&lt;String, Model&gt; dependencies(ModelContext modelContext) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    Map&lt;String, Model&gt; models = newHashMap();</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    for (ResolvedType resolvedType : dependencyProvider.dependentModels(modelContext)) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        ModelContext parentContext = ModelContext.fromParent(modelContext, resolvedType);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        Optional&lt;Model&gt; model = modelFor(parentContext).or(mapModel(parentContext, resolvedType));</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        if (model.isPresent()) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            models.put(model.get().getName(), model.get());</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    return models;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>dependencyProvider和modelProvider是同一个策略，默认接口，有两个实现类,一个是cache，一个是default</p><p>所以我们默认来看default的即可</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">@Override</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">public Set&lt;ResolvedType&gt; dependentModels(ModelContext modelContext) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    return concat(from(resolvedDependencies(modelContext))</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                  .filter(ignorableTypes(modelContext))</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                  .filter(not(baseTypes(modelContext))),</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                  schemaPluginsManager.dependencies(modelContext))</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        .toSet();</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>在默认配置中,最终是通过schemaPluginsManager的方法来解决ModelContext的转换</p><p>最终是通过<code>SyntheticModelProviderPlugin</code>来转换,但是springfox中他没有实现类,所以此处的Plugin是空的，不存在</p><p>所以此处的dependentModels返回的Set集合是空的</p><p>再来看<code>resolvedDependencies</code>的方法</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">private List&lt;ResolvedType&gt; resolvedDependencies(ModelContext modelContext) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    ResolvedType resolvedType = modelContext.alternateFor(modelContext.resolvedType(typeResolver));</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    if (isBaseType(ModelContext.fromParent(modelContext, resolvedType))) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      LOG.debug(&quot;Marking base type {} as seen&quot;, resolvedType.getSignature());</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      modelContext.seen(resolvedType);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      return newArrayList();</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    List&lt;ResolvedType&gt; dependencies = newArrayList(resolvedTypeParameters(modelContext, resolvedType));</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    dependencies.addAll(resolvedArrayElementType(modelContext, resolvedType));</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    dependencies.addAll(resolvedMapType(modelContext, resolvedType));</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    dependencies.addAll(resolvedPropertiesAndFields(modelContext, resolvedType));</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    dependencies.addAll(resolvedSubclasses(resolvedType));</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    return dependencies;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  }</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>从代码中我们能看到：</p><ul><li>首先因为ModelContext中属性是包含type的，所以默认拿到ResolvedType</li><li>通过拿到参数类型得到ResolvedType集合，如果有父类则递归调用.</li></ul><p>最终通过反射的方式拿到Model类型</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">private Optional&lt;Model&gt; reflectionBasedModel(ModelContext modelContext, ResolvedType propertiesHost) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    ImmutableMap&lt;String, ModelProperty&gt; propertiesIndex</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        = uniqueIndex(properties(modelContext, propertiesHost), byPropertyName());</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    LOG.debug(&quot;Inferred {} properties. Properties found {}&quot;, propertiesIndex.size(),</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">              Joiner.on(&quot;, &quot;).join(propertiesIndex.keySet()));</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    Map&lt;String, ModelProperty&gt; properties = newTreeMap();</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    properties.putAll(propertiesIndex);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    return Optional.of(modelBuilder(propertiesHost, properties, modelContext));</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">private Model modelBuilder(ResolvedType propertiesHost,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                           Map&lt;String, ModelProperty&gt; properties,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                           ModelContext modelContext) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    String typeName = typeNameExtractor.typeName(ModelContext.fromParent(modelContext, propertiesHost));</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    modelContext.getBuilder()</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        .id(typeName)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        .type(propertiesHost)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        .name(typeName)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        .qualifiedType(simpleQualifiedTypeName(propertiesHost))</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        .properties(properties)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        .description(&quot;&quot;)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        .baseModel(&quot;&quot;)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        .discriminator(&quot;&quot;)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        .subTypes(new ArrayList&lt;ModelReference&gt;());</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    return schemaPluginsManager.model(modelContext);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>构造Model的基础属性，包括类型，名称、描述、属性等信息</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">private List&lt;ModelProperty&gt; propertiesFor(ResolvedType type, ModelContext givenContext, String namePrefix) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    List&lt;ModelProperty&gt; properties = newArrayList();</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    BeanDescription beanDescription = beanDescription(type, givenContext);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    Map&lt;String, BeanPropertyDefinition&gt; propertyLookup = uniqueIndex(beanDescription.findProperties(),</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        BeanPropertyDefinitions.beanPropertyByInternalName());</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    for (Map.Entry&lt;String, BeanPropertyDefinition&gt; each : propertyLookup.entrySet()) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      LOG.debug(&quot;Reading property {}&quot;, each.getKey());</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      BeanPropertyDefinition jacksonProperty = each.getValue();</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      Optional&lt;AnnotatedMember&gt; annotatedMember</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          = Optional.fromNullable(safeGetPrimaryMember(jacksonProperty));</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      if (annotatedMember.isPresent()) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        properties.addAll(candidateProperties(type, annotatedMember.get(), jacksonProperty, givenContext, namePrefix));</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    return FluentIterable.from(properties).toSortedSet(byPropertyName()).asList();</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  }</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>获取属性集合配置的代码</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="总结">总结<a class="hash-link" href="#总结" title="标题的直接链接">​</a></h2><p>通过源码的一些研究,springfox主要的处理流程：</p><ul><li>收集该接口的参数类型Model</li><li>收集<code>@ApiOperation</code>注解的response类型Model</li><li>收集全局Model</li><li>收集接口返回类型Model</li><li>收集接口主键<code>@ApiResponses</code>状态码涉及的类型Model</li><li>在收集过程中使用了缓存策略,这样能提高解析效率</li></ul></div><footer class="theme-doc-footer docusaurus-mt-lg"><div class="theme-doc-footer-edit-meta-row row"><div class="col"></div><div class="col lastUpdated_vwxv"><span class="theme-last-updated">最后<!-- -->由 <b>xiaoyumin</b> <!-- -->于 <b><time datetime="2022-08-15T15:32:11.000Z">2022年8月15日</time></b> <!-- -->更新</span></div></div></footer></article><nav class="pagination-nav docusaurus-mt-lg" aria-label="文档分页导航"><a class="pagination-nav__link pagination-nav__link--prev" href="/docs/action/springfox/springfox9"><div class="pagination-nav__sublabel">上一页</div><div class="pagination-nav__label">springfox 源码分析(九) 文档初始化-分组</div></a><a class="pagination-nav__link pagination-nav__link--next" href="/docs/action/springfox/springfox11"><div class="pagination-nav__sublabel">下一页</div><div class="pagination-nav__label">springfox 源码分析(十一) 自定义添加Swagger Models功能实现</div></a></nav></div></div><div class="col col--3"><div class="tableOfContents_bqdL thin-scrollbar theme-doc-toc-desktop"><ul class="table-of-contents table-of-contents__left-border"><li><a href="#modelcontext" class="table-of-contents__link toc-highlight">ModelContext</a></li><li><a href="#初始化modelcontext-set集合" class="table-of-contents__link toc-highlight">初始化ModelContext Set集合</a><ul><li><a href="#operationmodelsproviderplugin" class="table-of-contents__link toc-highlight">OperationModelsProviderPlugin</a><ul><li><a href="#collectfromreturntype" class="table-of-contents__link toc-highlight">collectFromReturnType</a></li><li><a href="#collectparameters" class="table-of-contents__link toc-highlight">collectParameters</a></li><li><a href="#collectglobalmodels" class="table-of-contents__link toc-highlight">collectGlobalModels</a></li></ul></li><li><a href="#swaggeroperationmodelsprovider" class="table-of-contents__link toc-highlight">SwaggerOperationModelsProvider</a><ul><li><a href="#collectfromapioperation" class="table-of-contents__link toc-highlight">collectFromApiOperation</a></li><li><a href="#collectapiresponses" class="table-of-contents__link toc-highlight">collectApiResponses</a></li></ul></li></ul></li><li><a href="#modelcontext初始化" class="table-of-contents__link toc-highlight">ModelContext初始化</a></li><li><a href="#modelcontext转化为model" class="table-of-contents__link toc-highlight">ModelContext转化为Model</a></li><li><a href="#总结" class="table-of-contents__link toc-highlight">总结</a></li></ul></div></div></div></div></main></div></div><footer class="footer"><div class="container container-fluid"><div class="row footer__links"><div class="col footer__col"><div class="footer__title">文档指南</div><ul class="footer__items clean-list"><li class="footer__item"><a class="footer__link-item" href="/docs/quick-start">文档</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/community/simple-demo">示例</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/changelog">更新日志</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/upgrading/upgrading-to-v4">升级到v4.0</a></li></ul></div><div class="col footer__col"><div class="footer__title">社区</div><ul class="footer__items clean-list"><li class="footer__item"><a href="https://gitter.im/knife4j/knife4j" target="_blank" rel="noopener noreferrer" class="footer__link-item">Gitter<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a href="https://www.oschina.net/question/tag/swagger-bootstrap-ui" target="_blank" rel="noopener noreferrer" class="footer__link-item">开源中国<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li></ul></div><div class="col footer__col"><div class="footer__title">关注公众号</div><ul class="footer__items clean-list"><li class="footer__item"><img src="/images/website/qrcode.jpg" width="150"></li></ul></div><div class="col footer__col"><div class="footer__title">更多</div><ul class="footer__items clean-list"><li class="footer__item"><a href="https://docusaurus.io" target="_blank" rel="noopener noreferrer" class="footer__link-item">Docusaurus<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a href="https://gitee.com/xiaoym/knife4j" target="_blank" rel="noopener noreferrer" class="footer__link-item">Gitee<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a href="https://github.com/xiaoymin/swagger-bootstrap-ui" target="_blank" rel="noopener noreferrer" class="footer__link-item">GitHub<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li></ul></div></div><div class="footer__bottom text--center"><div class="footer__copyright">Apache License 2.0 | Copyright © 2018-2023-八一菜刀 浙ICP备18027673号-1 </div></div></div></footer></div>
<script src="/assets/js/runtime~main.e0db172c.js"></script>
<script src="/assets/js/main.c059fb6e.js"></script>
<!-- Google Tag Manager (noscript) -->
    <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-TKBX678" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
    <!-- End Google Tag Manager (noscript) --></body>
</html>